; 在C语言中可调用的hlt函数


[FORMAT "WCOFF"] ;制作目标文件的格式
[INSTRSET "i486p"] ;指定486CPU ，否则EAX这类32位寄存器无法识别
[BITS 32] ;设定为32位模式

[FILE "naskfunc.nas"]  ;源文件名信息

	
		GLOBAL	_io_hlt, _io_cli, _io_sti, _io_stihlt ;cpu操作
		GLOBAL	_io_in8,  _io_in16,  _io_in32  ;外设读数据
		GLOBAL	_io_out8, _io_out16, _io_out32 ;外设写数据
		GLOBAL	_io_load_eflags, _io_store_eflags ;状态寄存器设置
		GLOBAL  _io_load_cr0 ,_io_store_cr0 ;cr0操作
		GLOBAL  _write_mem8
		GLOBAL  _set_gdtr,_set_idtr  ;gdtr,idtr寄存器设置
		GLOBAL  _asm_handler_int20,_asm_handler_int21 ,_asm_handler_int27,_asm_handler_int2c ,_asm_handler_int0d;中断响应函数
		GLOBAL  _memtest_search ;内存大小检索
		GLOBAL  _load_tr ,_farjmp ,_farcall ; 操作tr寄存器 / 任务切换(远跳转) /远调用
		GLOBAL  _asm_api_main ,_start_app ,_asm_end_app;启动应用程序/关闭应用程序
		EXTERN  _handler_int20,_handler_int21,_handler_int2c,_handler_int27,_handler_int0d,_api_main;C语言写的中断函数,它们在汇编中被调用
[SECTION .text]


_write_mem8: ; void write_mem8(int addr ,int data)
	mov ECX,[ESP+4]
	mov al,[ESP+8]
	mov [ECX],al
	RET




_io_hlt: ; io_hlt(void) 这个是函数主体，  名称前必须多加一个_才可以被c语言链接 
	HLT
	RET ; 表示return


_io_cli: ;io_cli(void)禁止中断
	CLI
	RET


_io_sti: ;io_sti(void)
	STI
	RET


_io_stihlt: ;io_stihlt(void)
	STI
	HLT
	RET


_io_in8:	; int io_in8(int port);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,0
		IN		AL,DX
		RET

_io_in16:	; int io_in16(int port);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,0
		IN		AX,DX
		RET

_io_in32:	; int io_in32(int port);
		MOV		EDX,[ESP+4]		; port
		IN		EAX,DX
		RET

_io_out8:	; void io_out8(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		AL,[ESP+8]		; data
		OUT		DX,AL
		RET

_io_out16:	; void io_out16(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,[ESP+8]		; data
		OUT		DX,AX
		RET

_io_out32:	; void io_out32(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,[ESP+8]		; data
		OUT		DX,EAX
		RET

_io_load_eflags: ;  int io_load_eflags(void)
	PUSHFD
	POP EAX
	RET

_io_store_eflags:  ;io_store_eflags(int eflags)
	MOV EAX ,[ESP+4]
	PUSH EAX
	POPFD
	RET
_io_load_cr0: ; int io_load_cr0(void)
	MOV EAX ,CR0 
	RET 
_io_store_cr0: ;void io_store_cr0 (int cr0)
	MOV EAX,[ESP+4]
	MOV CR0,EAX
	RET
_set_gdtr:		; void set_gdtr(int limit, int addr);
		MOV		AX,[ESP+4]		; limit
		MOV		[ESP+6],AX
		LGDT	[ESP+6]
		RET

_set_idtr:		; void set_idtr(int limit, int addr);
		MOV		AX,[ESP+4]		; limit
		MOV		[ESP+6],AX
		LIDT	[ESP+6]
		RET

_asm_handler_int20:
		PUSH	ES
		PUSH	DS
		PUSHAD
		MOV		EAX,ESP
		PUSH	EAX
		MOV		AX,SS
		MOV		DS,AX
		MOV		ES,AX
		CALL	_handler_int20
		POP		EAX
		POPAD
		POP		DS
		POP		ES
		IRETD

_asm_handler_int21:
		PUSH ES 
		PUSH DS
		PUSHAD  ;PUSHAD指令压入32位寄存器，其入栈顺序是:EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI
		MOV EAX,ESP
		PUSH EAX
		MOV AX,SS
		MOV DS,AX
		MOV ES,AX
		CALL _handler_int21
		POP EAX
		POPAD
		POP DS
		POP ES
		IRETD


_asm_handler_int27:
		PUSH	ES
		PUSH	DS
		PUSHAD
		MOV		EAX,ESP
		PUSH	EAX
		MOV		AX,SS
		MOV		DS,AX
		MOV		ES,AX
		CALL	_handler_int27
		POP		EAX
		POPAD
		POP		DS
		POP		ES
		IRETD


_asm_handler_int2c:
		PUSH	ES
		PUSH	DS
		PUSHAD
		MOV		EAX,ESP
		PUSH	EAX
		MOV		AX,SS
		MOV		DS,AX
		MOV		ES,AX
		CALL	_handler_int2c
		POP		EAX
		POPAD
		POP		DS
		POP		ES
		IRETD

_asm_handler_int0d:
		STI
		PUSH	ES
		PUSH	DS
		PUSHAD
		MOV		EAX,ESP
		PUSH	EAX
		MOV		AX,SS
		MOV		DS,AX
		MOV		ES,AX
		CALL	_handler_int0d
		CMP		EAX,0		; 
		JNE		_asm_end_app		; 
		POP		EAX
		POPAD
		POP		DS
		POP		ES
		ADD		ESP,4			; INT 0x0d 中需要这句
		IRETD

_memtest_search:   ; int  memtest_search (unsigned int start ,unsigned int end );
	PUSH EBX 
	PUSH ESI 
	PUSH EDI 
	MOV EAX ,[ESP+4 +12]  ; eax = start (+12 是因为刚PUSH 了3个4字节的寄存器)
	MOV	ESI,0xaa55aa55			; pat0 = 0xaa55aa55;
	MOV	EDI,0x55aa55aa			; pat1 = 0x55aa55aa;
mt_loop: ;循环
	MOV EBX ,EAX
	ADD EBX ,0xffc  ;跳到从EAX开始的4KB中的最后4个字节 (一次检测4个KB)
	MOV EDX ,[EBX]  ;保存原值
	MOV [EBX],ESI   ; *p = pat0 ;
	XOR DWORD [EBX],0xffffffff ; *p ^=0xffffffff ; 
	CMP [EBX] ,EDI ;if (*p !=pat1) ,检查是否反转了
	JNE mt_fin
	XOR DWORD [EBX],0xffffffff ; *p ^=0xffffffff ; 
	CMP [EBX],ESI ; if(*p !=pat0) ,检查是否恢复了
	JNE mt_fin
	MOV [EBX],EDX 
	ADD EAX, 0x10000;表示该4KB内存可用 ，继续检测下一个4KB
	CMP EAX ,[ESP+8 +12] ;检测是否start >end
	JBE mt_loop
	POP EDI
	POP ESI
	POP EBX
	RET
mt_fin:
	MOV		[EBX],EDX  	; *p = old;
	POP		EDI
	POP		ESI
	POP		EBX
	RET


		
		
		
_load_tr:  ;void load_tr (int tr) ;
	LTR [ESP+4]  ;tr
	RET

_farjmp: ;void farjmp (int eip ,int cs) ;
	JMP FAR [ESP +4] 
	RET

_farcall:	; void farcall(int eip, int cs);
	CALL	FAR	[ESP+4]				; eip, cs
	RET

_asm_api_main:    ;api调用主函数
		; 
		STI
		PUSH	DS
		PUSH	ES
		PUSHAD		; 用于保存的pushad
		PUSHAD		; 用于传值的pushad
		MOV		AX,SS
		MOV		DS,AX		; 把操作系统段 存入ds和es
		MOV		ES,AX
		CALL	_api_main
		CMP		EAX,0		; 当eax不为0时结束
		JNE		_asm_end_app
		ADD		ESP,32
		POPAD
		POP		ES
		POP		DS
		IRETD
_asm_end_app:
;	EAX为tss.esp0的地址
		MOV		ESP,[EAX]
		MOV		DWORD [EAX+4],0  ;结束时令ss0为0
		POPAD
		RET					; 返回cmd_app


_start_app:		; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0);
		PUSHAD		; 将32位寄存器的值保存起来
		MOV		EAX,[ESP+36]	; EIP
		MOV		ECX,[ESP+40]	; CS
		MOV		EDX,[ESP+44]	; ESP
		MOV		EBX,[ESP+48]	; DS
		MOV		EBP,[ESP+52]	; tss.esp0
		MOV		[EBP  ],ESP		; 操作系统用的ESP
		MOV		[EBP+4],SS		; 操作系统用的ss
		MOV		ES,BX
		MOV		DS,BX
		MOV		FS,BX
		MOV		GS,BX
;	下面调整栈 以免用retf 跳转到应用程序
		OR		ECX,3			; 将应用程序用段号和3 进行or
		OR		EBX,3			; 将应用程序用段号和3 进行or
		PUSH	EBX				; 应用程序的ss
		PUSH	EDX				; 应用程序的esp
		PUSH	ECX				; 应用程序的cs
		PUSH	EAX				; 应用程序的eip
		RETF
;	应用程序结束后不会返回这里
